#include "Calculator.h"

#include <cassert>
#include <stack>

Calculator& Calculator::getInstance()
{
    static Calculator c;
    return c;
}

int Calculator::getPriority(char c)
{
    int priority = 0;
    switch (c)
    {
    case '(':
        priority = 0; break;
    case '+':
    case '-':
        priority = 1; break;
    case '*':
    case '/':
        priority = 2; break;
    case ')':
        priority = 3; break;
    default:
        assert(false && "getPriority():invalid argument");
    }
    return priority;
}


double Calculator::getValue(const std::string &input)
{
    double result;
    std::stack<char> opChar; 			// 操作符
    std::stack<int> opNum;				// 操作数
    char c;
    bool flag = false; 				// 标识前一字符是否是数字

    for (size_t i = 0; i < input.size(); ++i)
    {
        c = input[i];

        if (c == ' ')
        {
            continue;
        }
        else if (isdigit(c))
        {
            int num = c - '0';
            if (flag)
            {
                int a = opNum.top();
                opNum.pop();
                opNum.push(a * 10 + num);
            }
            else
            {
                opNum.push(num);
                flag = true;
            }
        }
        else
        {
            flag = false;
            if (opChar.empty() || c == '(')
            {
                opChar.push(c);
            }
            else if (c == ')')
            {
                char op = opChar.top();
                while (op != '(')
                {
                    int a = opNum.top();
                    opNum.pop();
                    int b = opNum.top();
                    opNum.pop();
                    switch (op)
                    {
                        case '+':
                        opNum.push(b + a); break;
                        case '-':
                        opNum.push(b - a); break;
                        case '*':
                        opNum.push(b * a); break;
                        case '/':
                        opNum.push(b / a); break;
                    }
                    opChar.pop();
                    op = opChar.top();
                }
                opChar.pop();
            }
            else if (getPriority(opChar.top()) > getPriority(c))
            {
                int a = opNum.top();
                opNum.pop();
                int b = opNum.top();
                opNum.pop();
                char op = opChar.top();
                opChar.pop();
                switch (op)
                {
                    case '+':
                    opNum.push(b + a); break;
                    case '-':
                    opNum.push(b - a); break;
                    case '*':
                    opNum.push(b * a); break;
                    case '/':
                    opNum.push(b / a); break;
                }
                opChar.push(c);
            }
            else
            {
                opChar.push(c);
            }
        }

    }

    while (!opChar.empty())
    {
        int a = opNum.top();
        opNum.pop();
        int b = opNum.top();
        opNum.pop();
        char op = opChar.top();
        opChar.pop();
        switch (op)
        {
            case '+':
            opNum.push(b + a); break;
            case '-':
            opNum.push(b - a); break;
            case '*':
            opNum.push(b * a); break;
            case '/':
            opNum.push(b / a); break;
        }
    }

    result = opNum.top();

    return result;
}
